/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2017        */
/*                                                                       */
/*   Portions COPYRIGHT 2017 STMicroelectronics                          */
/*   Portions Copyright (C) 2017, ChaN, all right reserved               */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various existing      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/

/* Includes ------------------------------------------------------------------*/
#include "diskio.h"
#include "ff_gen_drv.h"

#include "usbh_msc_scsi.h"
#include "usbh_msc_bot.h"
#include "usbh_msc_core.h"


extern USB_OTG_CORE_HANDLE  USB_OTG_Core;
extern USBH_HOST  USB_Host;


#define FS_USB		0

#define SECTOR_SIZE		512

/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
	BYTE pdrv				/* Physical drive nmuber (0..) */
)
{
	DSTATUS stat = STA_NOINIT;

	switch (pdrv)
	{
		case FS_USB :		/* STM32 USB Host 口外接U盘 */
			if(HCD_IsDeviceConnected(&USB_OTG_Core))
			{
				stat &= ~STA_NOINIT;
			}
			break;

		default :
			break;
	}
	return stat;
}



/*-----------------------------------------------------------------------*/
/* Get Disk Status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
	BYTE pdrv		/* Physical drive nmuber (0..) */
)
{
	DSTATUS stat = STA_NOINIT;

	switch (pdrv)
	{
		case FS_USB :
			stat = 0;
			break;

		default:
			break;
	}
	return stat;
}

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
{
	DRESULT res;

	switch (pdrv)
	{
		case FS_USB :
			//res = USB_disk_read(buff, sector, count);
			{
				BYTE status = USBH_MSC_OK;

				//if (Stat & STA_NOINIT) 	return RES_NOTRDY;

				if (HCD_IsDeviceConnected(&USB_OTG_Core))
				{
					do
					{
						status = USBH_MSC_Read10(&USB_OTG_Core, buff,sector,512 * count);
						USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);

						if (!HCD_IsDeviceConnected(&USB_OTG_Core))
						{
							break;
						}
					}
					while (status == USBH_MSC_BUSY );
				}

				if (status == USBH_MSC_OK)
				{
					res = RES_OK;
				}
				else
				{
					res = RES_ERROR;
				}
			}
			break;

		default:
			res = RES_PARERR;
			break;
	}
	return res;
}

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
{
	DRESULT res;

	switch (pdrv)
	{
		case FS_USB :
			//res = USB_disk_write(buff, sector, count);
			{
				BYTE status = USBH_MSC_OK;

				//if (drv || !count) return RES_PARERR;

				//if (Stat & STA_NOINIT) return RES_NOTRDY;
				//if (Stat & STA_PROTECT) return RES_WRPRT;

				if (HCD_IsDeviceConnected(&USB_OTG_Core))
				{
					do
					{
						status = USBH_MSC_Write10(&USB_OTG_Core,(BYTE*)buff,sector, 512 * count);
						USBH_MSC_HandleBOTXfer(&USB_OTG_Core, &USB_Host);

						if(!HCD_IsDeviceConnected(&USB_OTG_Core))
						{
							break;
						}
					}
					while(status == USBH_MSC_BUSY );

				}

				if (status == USBH_MSC_OK)
				{
					res = RES_OK;
				}
				else
				{
					res = RES_ERROR;
				}
			}
			break;

		default:
			res = RES_PARERR;
			break;
	}
	return res;
}
#endif


/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

#if _USE_IOCTL
DRESULT disk_ioctl (
	BYTE pdrv,		/* Physical drive nmuber (0..) */
	BYTE cmd,		/* Control code */
	void *buff		/* Buffer to send/receive control data */
)
{
	DRESULT res;

	switch (pdrv) {
	case FS_USB :
		{
			//if (drv) return RES_PARERR;
			res = RES_ERROR;

			//if (Stat & STA_NOINIT) return RES_NOTRDY;
			switch (cmd)
			{
				case CTRL_SYNC :		/* Make sure that no pending write process */
					res = RES_OK;
					break;

				case GET_SECTOR_COUNT :	/* Get number of sectors on the disk (DWORD) */
					*(DWORD*)buff = (DWORD) USBH_MSC_Param.MSCapacity;
					res = RES_OK;
					break;

				case GET_SECTOR_SIZE :	/* Get R/W sector size (WORD) */
					*(WORD*)buff = 512;
					res = RES_OK;
					break;

				case GET_BLOCK_SIZE :	/* Get erase block size in unit of sector (DWORD) */\
					*(DWORD*)buff = 512;
					res = RES_OK;
					break;

				default:
					res = RES_PARERR;
					break;
			}
			return res;
		}

	}
	return RES_PARERR;
}
#endif






// #if defined ( __GNUC__ )
// #ifndef __weak
// #define __weak __attribute__((weak))
// #endif
// #endif

// /* Private typedef -----------------------------------------------------------*/
// /* Private define ------------------------------------------------------------*/
// /* Private variables ---------------------------------------------------------*/
// extern Disk_drvTypeDef  disk;

// /* Private function prototypes -----------------------------------------------*/
// /* Private functions ---------------------------------------------------------*/

// /**
//   * @brief  Gets Disk Status
//   * @param  pdrv: Physical drive number (0..)
//   * @retval DSTATUS: Operation status
//   */
// DSTATUS disk_status (
// 	BYTE pdrv		/* Physical drive number to identify the drive */
// )
// {
//   DSTATUS stat;

//   stat = disk.drv[pdrv]->disk_status(disk.lun[pdrv]);
//   return stat;
// }

// /**
//   * @brief  Initializes a Drive
//   * @param  pdrv: Physical drive number (0..)
//   * @retval DSTATUS: Operation status
//   */
// DSTATUS disk_initialize (
// 	BYTE pdrv				/* Physical drive nmuber to identify the drive */
// )
// {
//   DSTATUS stat = RES_OK;

//   if(disk.is_initialized[pdrv] == 0)
//   {
//     disk.is_initialized[pdrv] = 1;
//     stat = disk.drv[pdrv]->disk_initialize(disk.lun[pdrv]);
//   }
//   return stat;
// }

// /**
//   * @brief  Reads Sector(s)
//   * @param  pdrv: Physical drive number (0..)
//   * @param  *buff: Data buffer to store read data
//   * @param  sector: Sector address (LBA)
//   * @param  count: Number of sectors to read (1..128)
//   * @retval DRESULT: Operation result
//   */
// DRESULT disk_read (
// 	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
// 	BYTE *buff,		/* Data buffer to store read data */
// 	DWORD sector,	        /* Sector address in LBA */
// 	UINT count		/* Number of sectors to read */
// )
// {
//   DRESULT res;

//   res = disk.drv[pdrv]->disk_read(disk.lun[pdrv], buff, sector, count);
//   return res;
// }

// /**
//   * @brief  Writes Sector(s)
//   * @param  pdrv: Physical drive number (0..)
//   * @param  *buff: Data to be written
//   * @param  sector: Sector address (LBA)
//   * @param  count: Number of sectors to write (1..128)
//   * @retval DRESULT: Operation result
//   */
// #if _USE_WRITE == 1
// DRESULT disk_write (
// 	BYTE pdrv,		/* Physical drive nmuber to identify the drive */
// 	const BYTE *buff,	/* Data to be written */
// 	DWORD sector,		/* Sector address in LBA */
// 	UINT count        	/* Number of sectors to write */
// )
// {
//   DRESULT res;

//   res = disk.drv[pdrv]->disk_write(disk.lun[pdrv], buff, sector, count);
//   return res;
// }
// #endif /* _USE_WRITE == 1 */

// /**
//   * @brief  I/O control operation
//   * @param  pdrv: Physical drive number (0..)
//   * @param  cmd: Control code
//   * @param  *buff: Buffer to send/receive control data
//   * @retval DRESULT: Operation result
//   */
// #if _USE_IOCTL == 1
// DRESULT disk_ioctl (
// 	BYTE pdrv,		/* Physical drive nmuber (0..) */
// 	BYTE cmd,		/* Control code */
// 	void *buff		/* Buffer to send/receive control data */
// )
// {
//   DRESULT res;

//   res = disk.drv[pdrv]->disk_ioctl(disk.lun[pdrv], cmd, buff);
//   return res;
// }
// #endif /* _USE_IOCTL == 1 */

// /**
//   * @brief  Gets Time from RTC
//   * @param  None
//   * @retval Time in DWORD
//   */
// __weak DWORD get_fattime (void)
// {
//   return 0;
// }

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

